Перейти к основному содержимому

3.07. Другие операции в SQL

Разработчику Аналитику Тестировщику
Архитектору Инженеру

Другие операции в SQL

Но SQL не ограничивается вышеуказанными командами. Дополнительные операции охватывают работу с таблицами, колонками, а также более продвинутыми задачами.


LIMIT

LIMIT — это ключевое слово в SQL, которое используется для ограничения количества строк, возвращаемых запросом. Оно полезно, когда нужно получить только определенное число строк из результата запроса, например, топ-N записей или выборку для пагинации.

SELECT * FROM users LIMIT 10;

Порой требуется получить только часть результатов — например, для постраничного вывода или отладки. Синтаксис может варьироваться в зависимости от диалекта SQL: в PostgreSQL и MySQL LIMIT n указывает максимальное число строк; в стандарте SQL и в некоторых других СУБД, таких как SQL Server, используется конструкция TOP или OFFSET ... FETCH. В SQLite и MySQL LIMIT также поддерживает смещение: LIMIT offset, count или LIMIT count OFFSET offset.


Фильтрация

Фильтрация данных – одна из самых важных операций в SQL, позволяет выбирать только нужные данные из таблиц. Оператор WHERE используется для указания условий отбора записей.

Примеры простых условий:

-- Выбрать всех пользователей старше 25 лет
SELECT * FROM users WHERE age > 25;

-- Выбрать товары с ценой от 100 до 500 рублей
SELECT * FROM products WHERE price BETWEEN 100 AND 500;

-- Выбрать заказы, сделанные сегодня
SELECT * FROM orders WHERE order_date = CURRENT_DATE;

Операторы SQL

Основные операторы в SQL сравнительные и логические. Рассмотрим их в таблице:

ОператорОписаниеПример
=РавноWHERE age = 30
<> или !=Не равноWHERE status <> 'active'
>БольшеWHERE price > 1000
<МеньшеWHERE rating < 3.5
>=Больше или равноWHERE quantity >= 10
<=Меньше или равноWHERE age <= 18
BETWEENВ диапазоне (включительно)WHERE price BETWEEN 50 AND 100
INВ списке значенийWHERE id IN (1, 5, 10)
NOT INНе в списке значенийWHERE country NOT IN ('US', 'UK')
IS NULLПроверка на NULLWHERE email IS NULL
IS NOT NULLПроверка на не-NULLWHERE phone IS NOT NULL
ANDИWHERE country = 'Russia' AND age > 25;
ORИЛИWHERE price < 100 OR price > 1000;
NOTНЕWHERE NOT status = 'cancelled';
LIKEПохоже на % - любое количество символов, _ - ровно один символWHERE name LIKE 'Ан%'; WHERE email LIKE '%@gmail.com'; WHERE name LIKE '____';

Сортировка

Сортировка – ключевая операция, которая сортирует результаты запроса по указанным столбцам (по возрастанию или убыванию), путём выполнения ORDER BY:

SELECT column1, column2
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC];

ASC (по умолчанию) – сортировка по возрастанию (A-Z, 0-9);

SELECT name, salary FROM employees ORDER BY salary ASC;

DESC – по убыванию (Z-A, 9-0).

SELECT name, salary FROM employees ORDER BY salary DESC;

Группировка

Группировка объединяет строки с одинаковыми значениями в группы – GROUP BY. Для каждой группы может быть вычислено агрегированное значение с использованием функций, таких как COUNT, SUM, AVG, MIN, MAX. Это агрегатные функции - о них мы поговорим отдельно.

Структура запроса с группировкой:

SELECT column, AGG_FUNC(expression)
FROM table
WHERE condition
GROUP BY column
HAVING group_condition
ORDER BY column;

Предложение GROUP BY определяет, по каким признакам производится объединение строк. Все уникальные комбинации значений в указанных столбцах формируют отдельную группу.

SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id;

Запрос возвращает количество сотрудников в каждом отделе.

Если в списке выборки присутствуют неагрегированные столбцы, они должны входить в GROUP BY. В противном случае запрос будет некорректным (за исключением некоторых диалектов, допускающих функциональную зависимость).

Можно группировать по нескольким столбцам:

SELECT department_id, job_title, AVG(salary)
FROM employees
GROUP BY department_id, job_title;

Это позволяет получить среднюю зарплату по каждой должности внутри отдела.

Кроме этого, фильтрация может быть не только через WHERE, но и через HAVING. Предложение HAVING используется для фильтрации групп, в отличие от WHERE, которое фильтрует отдельные строки до группировки.

WHERE применяется до GROUP BY — фильтрует строки таблицы.

HAVING применяется после GROUP BY — фильтрует результаты по агрегированным значениям.

-- Отделы, где средняя зарплата > 100000
SELECT department, AVG(salary) as avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 100000;
-- Только активные сотрудники (фильтр до группировки)
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
WHERE status = 'active'
GROUP BY department_id
HAVING AVG(salary) > 80000; -- Фильтр по средней зарплате (после группировки)

Здесь:

WHERE status = 'active' исключает уволенных до формирования групп.

HAVING AVG(salary) > 80000 оставляет только те отделы, где средняя зарплата превышает 80 000.

В HAVING можно использовать агрегатные функции (AVG, SUM, COUNT и т.д.), так как они рассчитываются на уровне групп. Строки с NULL в столбце группировки формируют отдельную группу. Все NULL значения считаются равными друг другу в контексте GROUP BY. Некоторые СУБД поддерживают расширенные формы группировки:

  • GROUP BY ROLLUP(...) — формирует итоговые строки по иерархии.
  • GROUP BY CUBE(...) — все возможные комбинации группировок.

Вложенные запросы (подзапросы)

Вложенный запрос — это SQL-выражение, встроенное в другое выражение (обычно в SELECT, FROM, WHERE или HAVING). Подзапрос выполняется первым, и его результат используется во внешнем запросе.


Классификация подзапросов

Скалярный подзапрос

Возвращает ровно одно значение (одну строку и один столбец). Может использоваться в списке выборки или условиях.

Пример:

SELECT name, salary, 
(SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;

Здесь подзапрос возвращает среднюю зарплату по всем сотрудникам и дублирует её в каждой строке результата.

Строчный подзапрос

Возвращает одну строку с несколькими столбцами. Используется, например, при сравнении составных значений.

Пример:

SELECT * FROM employees 
WHERE (name, salary) = (
SELECT name, salary FROM employees
WHERE id = 101
);
Табличный подзапрос

Возвращает набор строк и столбцов. Может использоваться в предложении FROM или WHERE.

Пример:

SELECT e.name, e.salary 
FROM (SELECT * FROM employees WHERE salary > 50000) AS e;

Подзапрос формирует временную таблицу «e» с сотрудниками, получающими более 50 000.

Подзапросы с оператором ALL

Оператор ALL используется для сравнения значения с каждым элементом результата подзапроса. Условие считается истинным, только если оно выполняется для всех значений.

Пример:

SELECT name, salary 
FROM employees
WHERE salary > ALL (
SELECT salary FROM employees WHERE department_id = 5
);

Запрос возвращает сотрудников, чья зарплата выше любой зарплаты в отделе 5 (то есть выше максимальной в этом отделе).

Аналогичный результат можно получить с помощью MAX, но ALL полезен в контексте обобщённых условий.

Многостолбцовые подзапросы

Многостолбцовые подзапросы позволяют сравнивать несколько столбцов одновременно. Часто используются с операторами IN, EXISTS, =, >, < и ALL.

Пример:

SELECT * FROM employees 
WHERE (department_id, salary) IN (
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
);

Запрос находит сотрудников с максимальной зарплатой в каждом отделе.

Коррелированные и некоррелированные подзапросы

Некоррелированный подзапрос — выполняется независимо от внешнего запроса. Его можно вычислить один раз.

Пример:

SELECT name FROM employees 
WHERE salary > (SELECT AVG(salary) FROM employees);

Коррелированный подзапрос — зависит от внешнего запроса и выполняется для каждой строки внешнего результата. Содержит ссылки на столбцы из внешнего запроса.

Пример:

SELECT e1.name, e1.salary, e1.department_id
FROM employees e1
WHERE e1.salary = (
SELECT MAX(e2.salary)
FROM employees e2
WHERE e2.department_id = e1.department_id
);

Для каждого сотрудника (e1) подзапрос находит максимальную зарплату в его отделе. Затем проверяется, равна ли зарплата сотрудника этому максимуму.

Такой подход позволяет находить топовых сотрудников по зарплате в каждом отделе, но требует осторожности из-за потенциальной нагрузки на производительность.